﻿using System.ComponentModel;
using System.IO;
using System.Text.Json;

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace TimeSpan.Models;

/// <summary>Json格式的配置类</summary>
internal class JsonConfig {

    /// <summary>配置根目录</summary>
    internal static string ConfigRootDir { get; set; } = string.Empty;

}

/// <summary>Json格式的配置类，实现了 <see cref="INotifyPropertyChanged"/> 接口</summary>
public class JsonConfig<T> : INotifyPropertyChanged, IConfig<T> where T : class, new() {

    private T config;

    public JsonConfig(string filename) {
        if (string.IsNullOrEmpty(filename)) { throw new ArgumentNullException(nameof(filename)); }
        FileName = filename;
        var absolutePath = Path.Combine(JsonConfig.ConfigRootDir, FileName);
        if (!File.Exists(absolutePath)) { File.Create(absolutePath).Dispose(); }

        try {
            var result = JsonSerializer.Deserialize<T>(File.ReadAllText(Path.Combine(JsonConfig.ConfigRootDir, FileName)));
            if (result != null) { config = result; } else { config = new(); }
        } catch (JsonException) {
            config = Activator.CreateInstance<T>();
        }

    }

    /// <summary>文件名，相对路径</summary>
    public string FileName { get; set; } = string.Empty;

    /// <summary>配置</summary>
    public T Config {
        get => config;
        set {
            if (config == value) { return; }
            config = value;
            PropertyChanged?.Invoke(this, new(nameof(Config)));
        }
    }

    /// <inheritdoc/>
    public event PropertyChangedEventHandler? PropertyChanged;

    /// <summary>加载配置</summary>
    public async Task LoadAsync() {
        var loaded = false;
        while (!loaded) {
            try {
                try {
                    var result = JsonSerializer.Deserialize<T>(await File.ReadAllTextAsync(Path.Combine(JsonConfig.ConfigRootDir, FileName)));
                    if (result != null) { Config = result; }
                } catch (JsonException) {
                    Config = Activator.CreateInstance<T>();
                }
                loaded = true;
            } catch {
                await Task.Delay(10);
            }
        }
    }

    /// <summary>保存配置</summary>
    public async Task SaveAsync() {
        var saved = false;
        while (!saved) {
            try {
                await File.WriteAllTextAsync(Path.Combine(JsonConfig.ConfigRootDir, FileName), JsonSerializer.Serialize(Config));
                saved = true;
            } catch {
                await Task.Delay(10);
            }
        }
    }

}

/// <summary>用于注册的扩展方法</summary>
public static class JsonConfigExtensions {

    /// <summary>设置配置的根目录</summary>
    public static IConfigurationBuilder SetConfigBasePath(this IConfigurationBuilder builder, string basePath) {
        JsonConfig.ConfigRootDir = basePath;
        if (!Directory.Exists(basePath)) { Directory.CreateDirectory(basePath); }
        return builder;
    }

    /// <summary>添加一个JsonConfig</summary>
    public static IServiceCollection AddJsonConfig<T>(this IServiceCollection services, string filename) where T : class, new() {
        services.AddSingleton<IConfig<T>>(new JsonConfig<T>(filename));
        return services;
    }

    /// <summary>添加一个Keyed JsonConfig服务，以文件名作为key</summary>
    public static IServiceCollection AddKeyedJsonConfig<T>(this IServiceCollection services, string filename) where T : class, new() {
        services.AddKeyedSingleton<IConfig<T>>(filename, new JsonConfig<T>(filename));
        return services;
    }

}